﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using SuperQuiz.Logic;
using SuperQuiz.Model;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;

namespace SuperQuiz.Logic
{
    public class OnEvaluateAnswerEventArgs : EventArgs
    {
        public int ScoredPoints { get; set; }
    }

    public class QuizPlay : BindableBase
    {
        public QuizPlay()
        { 
        }

        private Player _Player;
        [IgnoreDataMember]
        public Player Player
        {
            get { return this._Player; }
            set { this.SetProperty(ref this._Player, value); }
        }

        private int _FinalScore;
        public int FinalScore
        {
            get { return this._FinalScore; }
            set { this.SetProperty(ref this._FinalScore, value); }
        }

        private DateTime _DateStarted;
        public DateTime DateStarted
        {
            get { return this._DateStarted; }
            set { this.SetProperty(ref this._DateStarted, value); }
        }

        private DateTime _DateFinished;
        public DateTime DateFinished
        {
            get { return this._DateFinished; }
            set { this.SetProperty(ref this._DateFinished, value); }
        }

        private Quiz _Quiz;
        [IgnoreDataMember]
        public Quiz Quiz
        {
            get
            {
                if (_Quiz == null || !_Quiz.UniqueId.Equals(QuizId))
                {
                    _Quiz = QuizApplication.Instance.GetQuiz(QuizId);
                }
                return _Quiz;
            }
            set 
            {
                QuizId = value.UniqueId;
            }
        }

        private string _QuizId;
        public string QuizId
        {
            get { return this._QuizId; }
            set { this.SetProperty(ref this._QuizId, value); }
        }

        [IgnoreDataMember]
        public int CurrentAnswerIndex
        {
            get 
            {
                return SelectedAnswerIndexes[CurrentQuestionIndex];
            }
            set 
            {
                SelectedAnswerIndexes[CurrentQuestionIndex] = value;
                OnPropertyChanged("CurrentAnswerIndex");
            }
        }

        [IgnoreDataMember]
        public bool CurrentAnswerSelectionEnabled
        {
            get 
            {
                return !QuestionsLocked[CurrentQuestionIndex];
            }
            set 
            {
                QuestionsLocked[CurrentQuestionIndex] = !value;
                OnPropertyChanged("CurrentAnswerSelectionEnabled");
            }
        }

        private int _CurrentQuestionIndex;
        public int CurrentQuestionIndex
        {
            get 
            { 
                return this._CurrentQuestionIndex; 
            }
            set 
            { 
                this.SetProperty(ref this._CurrentQuestionIndex, value);
                OnPropertyChanged("IsNextEnabled");
                OnPropertyChanged("IsPreviousEnabled");
                OnPropertyChanged("IsFinishEnabled");
                OnPropertyChanged("CurrentQuestion");
                OnPropertyChanged("CurrentAnswerIndex");
                OnPropertyChanged("CurrentAnswerSelectionEnabled");
                OnPropertyChanged("IsNextVisible");
                OnPropertyChanged("IsFinishVisible");
                OnPropertyChanged("IsPreviousVisible");
            }
        }

        private List<int> _SelectedAnswerIndexes = new List<int>();
        public List<int> SelectedAnswerIndexes
        {
            get { return this._SelectedAnswerIndexes; }
            set { this.SetProperty(ref this._SelectedAnswerIndexes, value); }
        }

        private List<bool> _QuestionsLocked = new List<bool>();
        public List<bool> QuestionsLocked
        {
            get { return this._QuestionsLocked; }
            set { this.SetProperty(ref this._QuestionsLocked, value); }
        }

        [IgnoreDataMember]
        public QuizQuestion CurrentQuestion
        {
            get 
            {
                if (CurrentQuestionIndex == -1)
                    return null;
                return Quiz.Questions.ElementAt(CurrentQuestionIndex); 
            }
        }

        private Guid _UniqueId;
        public Guid UniqueId
        {
            get { return this._UniqueId; }
            set { this.SetProperty(ref this._UniqueId, value); }
        }

        public async Task<bool> Next()
        {
            if (CurrentQuestionIndex < Quiz.Questions.Count - 1)
            {
                if (Quiz.EvaluateAnswerOnNext)
                {
                    await EvaluateAnswer(CurrentQuestion);
                }
                if (Quiz.LockQuestionWhenNavigateToNext)
                {
                    SetQuestionLock(CurrentQuestionIndex, true);
                }
                CurrentQuestionIndex++;
                if (CurrentQuestionIndex == Quiz.Questions.Count - 1)
                {
                    HasReachedLastQuestion = true;
                }
                return true;
            }
            return false;
        }

        private async Task EvaluateAnswer(QuizQuestion question)
        {
            var questionIndex = Quiz.Questions.IndexOf(question);
            if (QuestionsLocked[questionIndex])
            {
                return;
            }
            var answerIndex = SelectedAnswerIndexes[questionIndex];
            var scoredPoints = 0;
            if (answerIndex != -1)
            {
                scoredPoints = question.Answers[answerIndex].Points;
            }
            if (Quiz.LockQuestionWhenEvaluated)
            {
                SetQuestionLock(questionIndex, true);
            }
            FinalScore += scoredPoints;

            var args = new OnEvaluateAnswerEventArgs(){
                ScoredPoints = scoredPoints,
            };
            OnEvaluateAnswerEvent(args);
        }

        private void SetQuestionLock(int questionIndex, bool lockState)
        {
            QuestionsLocked[questionIndex] = lockState;
            OnPropertyChanged("CurrentAnswerSelectionEnabled");
        }

        private void OnEvaluateAnswerEvent(OnEvaluateAnswerEventArgs args)
        {
            if (OnEvaluateAnswer != null)
            {
                OnEvaluateAnswer(this, args);
            }
        }

        public event EventHandler<OnEvaluateAnswerEventArgs> OnEvaluateAnswer;

        public async Task<bool> Previous()
        {
            if (CurrentQuestionIndex > 0 && Quiz.AllowPreviousNavigation)
            {
                if (Quiz.LockQuestionWhenNavigateToPrevious)
                {
                    SetQuestionLock(CurrentQuestionIndex, true);
                }
                CurrentQuestionIndex--;
                return true;
            }
            return false;
        }

        [IgnoreDataMember]
        public bool IsNextEnabled
        {
            get
            {
                return CurrentQuestionIndex < Quiz.Questions.Count - 1;
            }
        }

        [IgnoreDataMember]
        public bool IsPreviousVisible
        {
            get { return Quiz.AllowPreviousNavigation; }
        }

        [IgnoreDataMember]
        public bool IsPreviousEnabled
        {
            get { return CurrentQuestionIndex > 0 && Quiz.AllowPreviousNavigation; }
        }

        [IgnoreDataMember]
        public bool IsFinishVisible
        {
            get { return !IsResultsVisible && (HasReachedLastQuestion || !Quiz.ShowFinishOnlyWhenReachedLastQuestion) && Quiz.ShowFinishButton; }
        }

        [IgnoreDataMember]
        public bool IsNextVisible
        {
            get { return CurrentQuestionIndex <= Quiz.Questions.Count - 1; }
        }

        [IgnoreDataMember]
        public bool IsAskHelpVisible
        {
            get { return Quiz.AllowShareQuestions && !IsResultsVisible; }
        }

        private bool _HasReachedLastQuestion;
        public bool HasReachedLastQuestion
        {
            get { return this._HasReachedLastQuestion; }
            set 
            { 
                this.SetProperty(ref this._HasReachedLastQuestion, value);
                OnPropertyChanged("IsFinishVisible");
            }
        }

        private bool _IsResultsVisible;
        public bool IsResultsVisible
        {
            get { return this._IsResultsVisible; }
            set 
            { 
                this.SetProperty(ref this._IsResultsVisible, value);
                OnPropertyChanged("IsFinishVisible");
            }
        }

        public async Task Finish()
        {
            if (Quiz.EvaluateAnswerOnNext)
            {
                await EvaluateAnswer(CurrentQuestion);
            }
            else if (Quiz.EvaluateAnswersOnFinish)
            {
                FinalScore = 0;
                await EvaluateAllAnswers();
            }

            var results = new QuizResults() {
                FinalScore = this.FinalScore,
                Quiz = this.Quiz,
                DatePlayed = DateTime.Now,
                PlayerName = QuizApplication.Instance.GetLastPlayerName(this.Quiz.UniqueId),
            };
            var alternate = false;
            for (int i = 0; i < Quiz.Questions.Count; i++)
            {
                var question = Quiz.Questions[i];
                results.Items.Add(new QuizResultItem(){
                    Question = question,
                    MostCorrectAnswer = Quiz.ShowCorrectAnswerOnFinish ? question.Answers.OrderByDescending((a) => a.Points).FirstOrDefault() : null,
                    SelectedAnswerIndex = SelectedAnswerIndexes[i],
                    AlternateItem = alternate,
                });
                alternate = !alternate;
            }

            IsResultsVisible = true;
            Results = results;
        }

        private QuizResults _Results;
        public QuizResults Results
        {
            get { return this._Results; }
            set { this.SetProperty(ref this._Results, value); }
        }

        private async Task EvaluateAllAnswers()
        {
            foreach (var question in Quiz.Questions)
            {
                await EvaluateAnswer(question);
                await Task.Delay(250);
            }
        }

        public async Task Share(DataPackage requestData)
        {
            if (Results != null)
            {
                ShareResults(requestData);
            }
            else
            {
                await ShareQuestion(requestData);
            }
        }

        protected virtual async Task ShareQuestion(DataPackage requestData)
        {
            var resourceLoader = new ResourceLoader();
            requestData.Properties.Title = String.Format("{0} - {1}: {2}", Quiz.Category.Name, Quiz.Name, CurrentQuestion.Title);
            requestData.Properties.Description = resourceLoader.GetString("ShareQuestionDescription");
            await CurrentQuestion.FillDataPackage(requestData);
        }

        protected virtual void ShareResults(DataPackage requestData)
        {
            var resourceLoader = new ResourceLoader();
            requestData.Properties.Title = String.Format("{0} - {1}: {2} points!", Quiz.Category.Name, Quiz.Name, Results.FinalScore);
            requestData.Properties.Description = resourceLoader.GetString("SharePointsDescription");
            requestData.SetText(String.Format("I've just scored {0} points on quiz {1}!", Results.FinalScore, Results.Quiz.Name));
        }
    }
}
